#include "RedisManager.h"
#include <sstream>
#include <iostream>

RedisManager& RedisManager::instance() {
    static RedisManager instance;
    return instance;
}

RedisManager::RedisManager() : m_redisContext(nullptr) {}

RedisManager::~RedisManager() {
    disconnect();
}

bool RedisManager::connect(const std::string& host, int port) {
    if (m_redisContext) {
        redisFree(m_redisContext);
    }

    m_redisContext = redisConnect(host.c_str(), port);
    if (m_redisContext == nullptr || m_redisContext->err) {
        if (m_redisContext) {
            std::cerr << "Redis connection error: " << m_redisContext->errstr << std::endl;
            redisFree(m_redisContext);
            m_redisContext = nullptr;
        } else {
            std::cerr << "Redis connection error: can't allocate redis context" << std::endl;
        }
        return false;
    }
    return true;
}
void RedisManager::disconnect() {
    if (m_redisContext) {
        redisFree(m_redisContext);
        m_redisContext = nullptr;
    }
}
bool RedisManager::createUploadTask(long long userId, const std::string& fileMd5,
                                    const std::string& fileName, long long fileSize,
                                    const std::string& filePath) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "HMSET %s file_name %s file_size %lld uploaded_size 0 file_path %s status uploading",
                                                    taskKey.c_str(), fileName.c_str(), fileSize, filePath.c_str());

    if (!reply) return false;

    bool success = (reply->type != REDIS_REPLY_ERROR);
    freeReplyObject(reply);

    if (success) {
        // 添加到用户任务集合
        std::string userTasksKey = "user_tasks:" + std::to_string(userId);
        reply = (redisReply*)redisCommand(m_redisContext,
                                            "SADD %s %s", userTasksKey.c_str(), taskKey.c_str());

        success = (reply && reply->type != REDIS_REPLY_ERROR);
        if (reply) freeReplyObject(reply);
    }

    return success;
}
bool RedisManager::updateUploadProgress(long long userId, const std::string& fileMd5,
                                        long long uploadedSize) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "HSET %s uploaded_size %lld", taskKey.c_str(), uploadedSize);

    if (!reply) return false;

    bool success = (reply->type != REDIS_REPLY_ERROR);
    freeReplyObject(reply);
    return success;
}
bool RedisManager::pauseUploadTask(long long userId, const std::string& fileMd5) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "HSET %s status paused", taskKey.c_str());

    if (!reply) return false;

    bool success = (reply->type != REDIS_REPLY_ERROR);
    freeReplyObject(reply);
    return success;
}
bool RedisManager::resumeUploadTask(long long userId, const std::string& fileMd5) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "HSET %s status uploading", taskKey.c_str());

    if (!reply) return false;

    bool success = (reply->type != REDIS_REPLY_ERROR);
    freeReplyObject(reply);
    return success;
}

bool RedisManager::removeUploadTask(long long userId, const std::string& fileMd5) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;
    std::string userTasksKey = "user_tasks:" + std::to_string(userId);

    // 从用户任务集合中移除
    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "SREM %s %s", userTasksKey.c_str(), taskKey.c_str());

    bool success = (reply && reply->type != REDIS_REPLY_ERROR);
    if (reply) freeReplyObject(reply);

    if (success) {
        // 删除任务键
        reply = (redisReply*)redisCommand(m_redisContext, "DEL %s", taskKey.c_str());
        success = (reply && reply->type != REDIS_REPLY_ERROR);
        if (reply) freeReplyObject(reply);
    }

    return success;
}

bool RedisManager::getUploadTask(long long userId, const std::string& fileMd5,
                                 std::map<std::string, std::string>& taskInfo) {
    if (!m_redisContext) return false;

    std::string taskKey = "upload_task:" + std::to_string(userId) + ":" + fileMd5;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "HGETALL %s", taskKey.c_str());

    if (!reply || reply->type == REDIS_REPLY_ERROR || reply->elements % 2 != 0) {
        if (reply) freeReplyObject(reply);
        return false;
    }

    for (size_t i = 0; i < reply->elements; i += 2) {
        std::string key = reply->element[i]->str;
        std::string value = reply->element[i+1]->str;
        taskInfo[key] = value;
    }

    freeReplyObject(reply);
    return !taskInfo.empty();
}

std::vector<std::map<std::string, std::string>> RedisManager::getUserUploadTasks(long long userId) {
    std::vector<std::map<std::string, std::string>> tasks;
    if (!m_redisContext) return tasks;

    std::string userTasksKey = "user_tasks:" + std::to_string(userId);

    // 获取用户所有任务键
    redisReply* reply = (redisReply*)redisCommand(m_redisContext,
                                                    "SMEMBERS %s", userTasksKey.c_str());

    if (!reply || reply->type == REDIS_REPLY_ERROR) {
        if (reply) freeReplyObject(reply);
        return tasks;
    }

    for (size_t i = 0; i < reply->elements; i++) {
        std::string taskKey = reply->element[i]->str;

        // 获取每个任务的详细信息
        redisReply* taskReply = (redisReply*)redisCommand(m_redisContext,
                                                            "HGETALL %s", taskKey.c_str());

        if (taskReply && taskReply->type != REDIS_REPLY_ERROR && taskReply->elements % 2 == 0) {
            std::map<std::string, std::string> taskInfo;
            for (size_t j = 0; j < taskReply->elements; j += 2) {
                std::string key = taskReply->element[j]->str;
                std::string value = taskReply->element[j+1]->str;
                taskInfo[key] = value;
            }
            tasks.push_back(taskInfo);
        }

        if (taskReply) freeReplyObject(taskReply);
    }

    freeReplyObject(reply);
    return tasks;
}
bool RedisManager::executeCommand(const std::string& cmd, std::string& replyStr) {
    if (!m_redisContext) return false;

    redisReply* reply = (redisReply*)redisCommand(m_redisContext, cmd.c_str());
    if (!reply) return false;

    bool success = (reply->type != REDIS_REPLY_ERROR);
    if (success) {
        if (reply->type == REDIS_REPLY_STRING) {
            replyStr = reply->str;
        } else if (reply->type == REDIS_REPLY_INTEGER) {
            replyStr = std::to_string(reply->integer);
        }
    }

    freeReplyObject(reply);
    return success;
}
